﻿using System;
using System.Collections.Generic;

namespace Sustainalytics.Utils
{
    public static class NumberExtensions
    {
        public static string GetOrdinalName(this Int32 cardinal)
        {
            string[] ordinals;
            #region ordinals
            {
                ordinals = new string[]
                    {
                        "zeroth",
                        "first",
                        "second",
                        "third",
                        "fourth",
                        "fifth",
                        "sixth",
                        "seventh",
                        "eighth",
                        "ninth",
                        "tenth",
                        "eleventh",
                        "twelfth",
                        "thirteenth",
                        "fourteenth",
                        "fifteenth",
                        "sixteenth",
                        "seventeenth",
                        "eighteenth",
                        "nineteenth",
                        "twentieth"
                    };
            }
            #endregion ordinals

            Dictionary<int, string> tens;
            #region tens
            {
                tens = new Dictionary<int, string>
                {
                    { 20, "twenty" },
                    { 30, "thirty" },
                    { 40, "forty" },
                    { 50, "fifty" },
                    { 60, "sixty" },
                    { 70, "seventy" },
                    { 80, "eighty" },
                    { 90, "ninety" }
                };
            }
            #endregion tens

            Dictionary<int, string> ordinalTens;
            #region ordinalTens
            {
                ordinalTens = new Dictionary<int, string>
                {
                    { 30, "thirtieth" },
                    { 40, "fortieth" },
                    { 50, "fiftieth" },
                    { 60, "sixtieth" },
                    { 70, "seventieth" },
                    { 80, "eightieth" },
                    { 90, "ninetieth" },
                    { 100, "one hundredth" },
                    { 1000, "one thousandth" },
                    { 1000000, "one millionth" }
                };
            }
            #endregion ordinalTens
            
            string str;
            
            if (cardinal <= 20) {
                str = ordinals[cardinal];
            }
            else {
                if (cardinal % 10 == 0) {
                    str = ordinalTens[cardinal];
                }
                else {
                    str = tens[cardinal - (cardinal % 10)] + ordinals[cardinal % 10];
                }
            }

            return str;
        }

        public static bool NearlyEq<T, V>(this T a, V b, float epsilon = 1e-6f)
        {
            if (a != null && b != null)
                return Convert.ToDouble(a).NearlyEq(Convert.ToDouble(b), epsilon);
            else
                return a == null && b == null;
        }

        public static bool NearlyEq(this double a, double b, float epsilon = 1e-6f)
        {
            double absA = Math.Abs(a);
            double absB = Math.Abs(b);
            double diff = Math.Abs(a - b);

            if (a.Equals(b))
            {
                // shortcut, handles infinities
                return true;
            }
            if (a.Equals(0) || b.Equals(0) || diff < Double.Epsilon)
            {
                // a or b is zero or both are extremely close to it
                // relative error is less meaningful here
                return diff < epsilon;
            }
            // use relative error
            return diff / (absA + absB) < epsilon;
        }
    }
}
